package vfs.persist.association.impl;

import vfs.except.VFSModificationException;
import vfs.except.VFSCreationException;
import vfs.except.VFSEntityException;
import vfs.except.VFSPersistenceException;
import java.sql.ResultSet;
import java.sql.Connection;
import vfs.persist.entity.build.impl.VFSNodeBuilder;
import vfs.persist.util.VFSIterator;
import vfs.persist.association.VFSPathManager;
import vfs.obj.entity.VFSNode;
import vfs.filter.VFSFilter;
import vfs.obj.entity.VFSPathAncestor;
import vfs.obj.entity.VFSPathDescendant;
import vfs.persist.entity.build.impl.VFSPathAncestorBuilder;
import vfs.persist.entity.build.impl.VFSPathDescendantBuilder;
import java.util.Iterator;

import static vfs.persist.util.VFSPersistUtil.*;

/**
 *
 * @author Matthew Eavenson <durandal@uga.edu>
 */
public class VFSPathManagerImpl implements VFSPathManager{
    private Connection conn;
    private VFSPathAncestorBuilder aBuilder;
    private VFSPathDescendantBuilder pBuilder;
    private VFSNodeBuilder nBuilder;
    private final String TABLE = "vfsPath";
    private final String TLINK = "ancestor";
    private final String ULINK = "descendant";
    
    public VFSPathManagerImpl(Connection conn){
        this.conn = conn;
        aBuilder = new VFSPathAncestorBuilder();
        pBuilder = new VFSPathDescendantBuilder();
        nBuilder = new VFSNodeBuilder();
    }
    
    @Override
    public Iterator<VFSPathAncestor> getAncestors(VFSNode descendant, VFSFilter filter){
        if(descendant == null) throw new VFSEntityException("getAncestors: no descendant given");
        long uid = descendant.getId();
        if(filter != null) filter.setPrefix(" AND ");
        String query = "SELECT "+aBuilder.KEY+", "+aBuilder.FIELDS+", length "
                     + "FROM "+TABLE+" JOIN "+aBuilder.TABLE+" ON "+TLINK+" = "+aBuilder.KEY
                     +" WHERE "+ULINK+" = " + uid + (filter == null ? "" : filter);
        try{
            ResultSet rs = queryDB(conn, query);
            return new VFSIterator<VFSPathAncestor>(rs, aBuilder);
        }catch(VFSPersistenceException ex){
            return new VFSIterator<VFSPathAncestor>(null, aBuilder);
        }
    }
    
    @Override
    public Iterator<VFSPathDescendant> getDescendants(VFSNode ancestor, VFSFilter filter){
        if(ancestor == null) throw new VFSEntityException("getDescendants: no ancestor given");
        long tid = ancestor.getId();
        if(filter != null) filter.setPrefix(" AND ");
        String query = "SELECT "+pBuilder.KEY+", "+pBuilder.FIELDS+", length "
                     + "FROM "+TABLE+" JOIN "+pBuilder.TABLE+" ON "+ULINK+" = "+pBuilder.KEY
                     +" WHERE "+TLINK+" = " + tid + (filter == null ? "" : filter);
        try{
            ResultSet rs = queryDB(conn, query);
            return new VFSIterator<VFSPathDescendant>(rs, pBuilder);
        }catch(VFSPersistenceException ex){
            return new VFSIterator<VFSPathDescendant>(null, pBuilder);
        }
    }
    
    @Override
    public VFSNode getAncestor(VFSNode descendant, int length){
        if(descendant == null) throw new VFSEntityException("getAncestor: no descendant given");
        long uid = descendant.getId();
        String query = "SELECT "+nBuilder.KEY+", "+nBuilder.FIELDS
                     +" FROM "+TABLE+" JOIN "+nBuilder.TABLE+" ON "+TLINK+" = "+nBuilder.KEY
                     +" WHERE "+ULINK+" = "+uid+" AND length = "+length;
        try{
            ResultSet rs = queryDB(conn, query);
            if(rs.next()) return nBuilder.build(rs);
        }catch(Exception ex){
            // TODO -- LOG THIS!!
        }
        return null;
    }
    
    @Override
    public Iterator<VFSNode> getDescendants(VFSNode ancestor, int length){
        if(ancestor == null) throw new VFSEntityException("getDescendants: no ancestor given");
        long tid = ancestor.getId();
        String query = "SELECT "+nBuilder.KEY+", "+nBuilder.FIELDS+" FROM "+TABLE+" JOIN "+nBuilder.TABLE+
                " ON "+ULINK+" = "+nBuilder.KEY+" WHERE "+TLINK+" = "+tid+" AND length = "+length;
        try{
            ResultSet rs = queryDB(conn, query);
            return new VFSIterator<VFSNode>(rs, nBuilder);
        }catch(VFSPersistenceException ex){
            return new VFSIterator<VFSNode>(null, nBuilder);
        }
    }
    
    @Override
    public void addPath(VFSNode ancestor, VFSNode descendant, int length){
        if(ancestor == null) throw new VFSEntityException("addPath: no ancestor given");
        if(descendant == null) throw new VFSEntityException("addPath: no descendant given");
        long tid = ancestor.getId();
        long uid = descendant.getId();
        String update = "INSERT INTO " + TABLE + " (" + TLINK + "," + ULINK + ", length)" +
                " VALUES ( " + tid + ", " + uid + ", "+length+" )";
        try{
            updateDB(conn, update);
        }catch(VFSPersistenceException ex){
            throw new VFSCreationException(ex);
        }
    }
    
    @Override
    public void removePath(VFSNode ancestor, VFSNode descendant){
        if(ancestor == null) throw new VFSEntityException("removePath: no ancestor given");
        if(descendant == null) throw new VFSEntityException("removePath: no descendant given");
        long tid = ancestor.getId();
        long uid = descendant.getId();
        String update = "DELETE FROM " + TABLE +
                " WHERE " + TLINK + " = " + tid +
                " AND " + ULINK + " = " + uid;
        try{
            updateDB(conn, update);
        }catch(VFSPersistenceException ex){
            throw new VFSModificationException(ex);
        }
    }
    
    @Override
    public void removeAll(VFSNode node){
        if(node == null) throw new VFSEntityException("removeAll: no node given");
        long id = node.getId();
        String update = "DELETE FROM " + TABLE +
                " WHERE " + TLINK + " = " + id +
                " OR "+ULINK+" = "+id;
        try{
            updateDB(conn, update);
        }catch(VFSPersistenceException ex){
            throw new VFSModificationException(ex);
        }
    }
    
    @Override
    public void removeAncestors(VFSNode node, int length){
        if(node == null) throw new VFSEntityException("removeAncestors: no node given");
        long id = node.getId();
        String update = "DELETE FROM " + TABLE +
                " WHERE "+ULINK+" = "+id+" AND length >= "+length;
        try{
            updateDB(conn, update);
        }catch(VFSPersistenceException ex){
            throw new VFSModificationException(ex);
        }
    }
    
    @Override
    public void alterPath(VFSNode ancestor, VFSNode descendant, int length){
        if(ancestor == null) throw new VFSEntityException("alterPath: no ancestor given");
        if(descendant == null) throw new VFSEntityException("alterPath: no descendant given");
        long tid = ancestor.getId();
        long uid = descendant.getId();
        String update = "UPDATE " + TABLE +
                " SET length = "+length + 
                " WHERE " + TLINK + " = " + tid +
                " AND " + ULINK + " = " + uid;
        try{
            updateDB(conn, update);
        }catch(VFSPersistenceException ex){
            throw new VFSModificationException(ex);
        }
    }
    
}
